#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <string.h>
#include <netdb.h>

#include "saron.hpp"

Saron::Saron(char* envp[])
{
    this->printSplashScreen();

    this->config = new Config("saron.conf", envp);
}

Saron::~Saron()
{
    // Nothic
}

void Saron::printSplashScreen()
{
    std::cout << "     _______.     ___      .______        ______   .__   __." << "\n";
    std::cout << "    /       |    /   \\     |   _  \\      /  __  \\  |  \\ |  |" << "\n";
    std::cout << "   |   (----`   /  ^  \\    |  |_)  |    |  |  |  | |   \\|  |" << "\n";
    std::cout << "    \\   \\      /  /_\\  \\   |      /     |  |  |  | |  . \\  |" << "\n";                            
    std::cout << ".----)   |    /  _____  \\  |  |\\  \\----.|  `--'  | |  |\\   |" << "\n";       
    std::cout << "|_______/    /__/     \\__\\ | _| `._____| \\______/  |__| \\__|" << "\n";       
    std::cout << "\tBy Piotr (Piomek) Merski and Sławomir Wójćik\n";
}

int Saron::waitToConnect()
{
    std::cout << "Wait to connecting on " << this->config->pInt("port") <<"..." << "\n";

    int sockfd, newsockfd;
    socklen_t clilen;
    struct sockaddr_in serv_addr, cli_addr;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
     
    if (sockfd == -1)
	perror("ERROR opening socket");

    serv_addr.sin_family = PF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(this->config->pInt("port"));

    int yes = 1;

    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
	perror("ERROR on setsockopt");
	
    int bind_return = bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));

    if (bind_return == -1)
	perror("ERROR on binding");

    do
    {
	std::cout << "Czekam na połączenie ..." << "\n";

	listen(sockfd, 5);
     
	clilen = sizeof(cli_addr);
    
	newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
	std::cout << "Jest połaczenie" << "\n";

	pid_t pid = fork();

	if (pid == 0)
	{
	    // Dziecko

	    close(sockfd);

	    if (newsockfd == -1)
		perror("ERROR on accept");

	    /* */

	    struct sockaddr klientInfo;
	    socklen_t kis = sizeof(klientInfo);    

	    int retInfo = getpeername(newsockfd, &klientInfo, &kis);

	    if (retInfo == -1)
		perror("ERROR on getpeername");

	    char * ip = inet_ntoa( ( (struct sockaddr_in *) &klientInfo )->sin_addr);

	    std::cout << "Połączony z " << ip << "\n";

	    /* */

	    int rh = readHeader(newsockfd);

	    if (rh != 0)
		perror("ERROR on readHeader");

	    /* */

	    close(newsockfd);

	    std::cout << "Połączenie zakończone" << "\n";

	    exit(0);
	}
	else if (pid > 0)
	{
	    //Rodzic

	    close(newsockfd);
	}
	else
	{
	    perror("ERROR on fork");
	}
    } while (this->config->pBool("loop"));

    close(sockfd);

    return 0;
}

int Saron::readHeader(int socked)
{
    //hread(socked);
    //char doWyslania[] = "OK\n";
    //hsend(socked, doWyslania, (size_t) sizeof(doWyslania));

    //hread(socked);

    char doWyslania2[] = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
	"\r\n";

    hsend(socked, doWyslania2, (size_t) sizeof(doWyslania2));

    //while (true)
    hread(socked);

//hread(socked);

    return 0;
}

int Saron::hread(int socked)
{
    char buffer[256];
    int n = 0;

    bzero(buffer, 256);
     
    n = read(socked, buffer, 255);
	
    if (n == -1)
	perror("ERROR reading from socket"); 

    const char * odebraneNoln = ((std::string) buffer).substr(0, n-1).c_str(); // Usunięcie na końcu znaku \n

    printf("<< \"%s\" (%i/255 bajtów) \n", odebraneNoln, n);

    return 0;
}

int Saron::hsend(int socked, char* tekst, size_t size)
{
    int n = 0;

    n = write(socked, tekst, size);
    
    if (n == -1)
	perror("ERROR writing to socket");

    //const char * doWyslaniaNoln = ((std::string) tekst).substr(0, size-2).c_str(); // Usunięcie na końcu znaku \n

    printf(">> \"%s\" (%i/%i bajtów)\n", tekst, n, size);

    return 0;
}
